在MDN講解function:prototype
的內容中,有列了一張描述function:prototype
的Property attributes的表格,因此本文會來解釋什麽是屬性描述器。
屬性描述器(Property descriptors)主要用於確定查看與設定Property的attributes,這些描述器讓我們能查看某個屬性(property)的…屬性(attribute),擁有他所描述的property attribute同名的property,也就是說屬性描述器這個物件中使用property列出attribute,並使用相應的方法來讀取和修改它們。
屬性描述器分為主要兩類:資料描述(data descriptor)跟訪問器描述(accessor descriptor)。資料描述是一個具有值的property,訪問器描述則是主要由getter/setter組成的函式property。
(看書或查資料的時候,有些內容會把property翻成特性,但感覺這樣使用很容易混淆,因此接下來的內容會直接使用property
跟attribute
來區分差異)
如何看到property的attribute:
const contestant = {
contestantId: 1
}
console.log(Object.getOwnPropertyDescriptor(contestant,'contestantId'));//{ value: 1, writable: true, enumerable: true, configurable: true }
上面分別印出value
、writable
、enumerable
、configurable
,它們組成資料描述。
資料描述除了用來表示property值的value
,分別有writable
、enumerable
、configurable
。
我們可以使用Object.defineProperty()
方法更改這些property,其語法為Object.defineProperty(obj,propertyName, descriptor)
,要注意的是propertyName
需要單引號或雙引號括住。
writable
決定property的值能不能被修改。如果設定為true
,那麽property值就可以被更改。
在前面介紹屬性描述器時,使用以下的物件來示範屬性描述:
const contestant = {
contestantId: 1,
}
再使用Object.defineProperty()
方法來更改contestantId
property的writable:
Object.defineProperty(contestant,'contestantId',{
writable: false,
})
//嘗試更改,就會發生錯誤
contestant.contestantId = 30//TypeError: Cannot assign to read only property 'contestantId' of object '#<Object>'
enumerable
決定property是否可被列舉的。在使用前幾天提到for-in
、Object.keys()
這兩個方法的時候,就是判斷property是否為enumerable
,決定這個property能不能被這些方法使用。
在下面的範例中,我們將contestantId
property的enumerable
設置為 false
:
const contestant = {
contestantId: 1,
contestantName: "Alice",
}
Object.defineProperty(contestant, 'contestantId', {
enumerable:false,
// configurable:false,
})
for(const key in contestant){
console.log(key);//contestantName
}
可以看到在使用for-in
時,只有contestantName
被迭代,contestantId
就像被隱藏起來。
如果只想知道某個property能不能被列舉,可以使用Object.prototype.propertyIsEnumerable()
方法確認,使用這個方法會回傳一個Boolean值,來表示是否能列舉。
const contestant = {
contestantId: 1,
contestantName: "Alice",
}
Object.defineProperty(contestant, 'contestantId', {
enumerable:false,
})
console.log(contestant.propertyIsEnumerable('contestantId'))//false;
在剛才已經設定contestant.contestantId
的enumerable是false
,因此Object.prototype.propertyIsEnumerable()
回傳一個false
回來。
configurable
指的是property的attribute能不能被修改。如果是true
,property就可以被刪除,也可以任意修改attribute。一旦把true
改成false
,就無法再把configurable
改回true
。
configurable
是false
的話,也不能更改enumerable
,無法把writable
的false
改回true
以下示範被configurable
影響會發生什麽:
const contestant = {
contestantId: 1,
}
// 'contestantId'的configurable attribute改為false
Object.defineProperty(contestant, 'contestantId', {
configurable:false
})
// 嘗試修改'contestantId'的writable的attribute,不會報錯
Object.defineProperty(contestant, 'contestantId', {
writable:false
})
// 嘗試將 'contestantId'的configurable的attribute設置為true會報錯
Object.defineProperty(contestant, 'contestantId', {
writable:true,//TypeError: Cannot redefine property: contestantId
})
// 嘗試將 'contestantId' 的enumerable的attribute設置false,將會報錯
Object.defineProperty(contestant, 'contestantId', {
configurable:true,
enumerable:false
//TypeError: Cannot redefine property: contestantId
唯一能被更改的attribute只有在writable
是true
的狀況。假設在configurable是false
的狀態下把writable
改成false
,就會像前面說,無法再把writable
改回true
。
讓我們來讀這張表格:Function.prototype
的property attributes,是可以寫入、不可列舉、不可配置的,也告訴我們Function.prototype
的attributes
都無法被修改,最多就只能修改property的值。
(本文接續〈Day9〉屬性描述器(下))